package com.ruoyi.framework.security;

import com.ruoyi.common.utils.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * Token管理服务
 * 提供token黑名单、刷新、统计等功能
 * 
 * @author ruoyi
 */
@Service
public class TokenManagementService
{
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    
    private static final String REDIS_BLACKLIST_PREFIX = "agg:blacklist:";
    private static final String REDIS_TOKEN_PREFIX = "agg:token:";
    private static final String REDIS_USER_CACHE_PREFIX = "agg:user:cache:";
    private static final String REDIS_AUTH_STATS_PREFIX = "agg:auth:stats:";
    
    /**
     * 将token加入黑名单
     */
    public void blacklistToken(String token)
    {
        try {
            // 获取token过期时间
            Long expirationTime = jwtTokenUtil.getExpirationDateFromToken(token).getTime();
            Long currentTime = System.currentTimeMillis();
            
            // 计算剩余过期时间
            long ttl = Math.max(0, expirationTime - currentTime) / 1000;
            
            if (ttl > 0) {
                String key = REDIS_BLACKLIST_PREFIX + token;
                redisTemplate.opsForValue().set(key, "blacklisted", ttl, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            System.err.println("加入token黑名单失败: " + e.getMessage());
        }
    }
    
    /**
     * 检查token是否在黑名单
     */
    public boolean isTokenBlacklisted(String token)
    {
        try {
            String key = REDIS_BLACKLIST_PREFIX + token;
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 刷新token
     */
    public String refreshToken(String oldToken)
    {
        try {
            // 验证旧token
            String username = jwtTokenUtil.getUsernameFromToken(oldToken);
            if (username == null || !jwtTokenUtil.validateToken(oldToken, username)) {
                return null;
            }
            
            // 获取用户ID
            Long userId = jwtTokenUtil.getUserIdFromToken(oldToken);
            if (userId == null) {
                return null;
            }
            
            // 生成新token
            String newToken = jwtTokenUtil.generateToken(userId, username);
            
            // 将旧token加入黑名单
            blacklistToken(oldToken);
            
            // 更新Redis中的token
            if (username.startsWith("agg_")) {
                String redisKey = REDIS_TOKEN_PREFIX + userId;
                redisTemplate.opsForValue().set(redisKey, newToken);
            }
            
            return newToken;
            
        } catch (Exception e) {
            System.err.println("刷新token失败: " + e.getMessage());
            return null;
        }
    }
    
    /**
     * 踢出用户（单点登录）
     */
    public void kickUser(Long userId)
    {
        try {
            // 删除Redis中的token
            String redisKey = REDIS_TOKEN_PREFIX + userId;
            String oldToken = (String) redisTemplate.opsForValue().get(redisKey);
            
            if (oldToken != null) {
                // 将旧token加入黑名单
                blacklistToken(oldToken);
                // 删除Redis中的token
                redisTemplate.delete(redisKey);
            }
            
            // 清除用户缓存
            String userCacheKey = REDIS_USER_CACHE_PREFIX + userId;
            redisTemplate.delete(userCacheKey);
            
        } catch (Exception e) {
            System.err.println("踢出用户失败: " + e.getMessage());
        }
    }
    
    /**
     * 清除用户缓存
     */
    public void clearUserCache(Long userId)
    {
        try {
            String key = REDIS_USER_CACHE_PREFIX + userId;
            redisTemplate.delete(key);
        } catch (Exception e) {
            System.err.println("清除用户缓存失败: " + e.getMessage());
        }
    }
    
    /**
     * 记录认证统计
     */
    public void recordAuthStats(String type, boolean success)
    {
        try {
            String today = java.time.LocalDate.now().toString();
            String key = REDIS_AUTH_STATS_PREFIX + today + ":" + type;
            
            if (success) {
                redisTemplate.opsForValue().increment(key + ":success");
            } else {
                redisTemplate.opsForValue().increment(key + ":failure");
            }
            
            // 设置过期时间为7天
            redisTemplate.expire(key + ":success", 7, TimeUnit.DAYS);
            redisTemplate.expire(key + ":failure", 7, TimeUnit.DAYS);
            
        } catch (Exception e) {
            // 统计失败不影响主流程
        }
    }
    
    /**
     * 获取认证统计
     */
    public AuthStats getAuthStats(String type, String date)
    {
        try {
            String key = REDIS_AUTH_STATS_PREFIX + date + ":" + type;
            
            Object successObj = redisTemplate.opsForValue().get(key + ":success");
            Object failureObj = redisTemplate.opsForValue().get(key + ":failure");
            
            long success = successObj != null ? (Long) successObj : 0;
            long failure = failureObj != null ? (Long) failureObj : 0;
            
            return new AuthStats(success, failure);
            
        } catch (Exception e) {
            return new AuthStats(0, 0);
        }
    }
    
    /**
     * 认证统计数据结构
     */
    public static class AuthStats
    {
        private long successCount;
        private long failureCount;
        
        public AuthStats(long successCount, long failureCount)
        {
            this.successCount = successCount;
            this.failureCount = failureCount;
        }
        
        public long getSuccessCount() { return successCount; }
        public long getFailureCount() { return failureCount; }
        public long getTotalCount() { return successCount + failureCount; }
        public double getSuccessRate() { 
            long total = getTotalCount();
            return total > 0 ? (double) successCount / total * 100 : 0;
        }
    }
}
